package tests.simulation;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import p2pcdnsim.cdn.CDN;
import p2pcdnsim.cdn.CDNConstructor;
import p2pcdnsim.cdn.DynamicReplicaPlacementNaive;
import p2pcdnsim.network.NetworkTopology;
import p2pcdnsim.network.TopologyConstructor;
import p2pcdnsim.report.Bandwidth;
import p2pcdnsim.report.SimReporter;
import p2pcdnsim.xml.StandardXMLHandler;
import p2pcdnsim.xml.VideoObjectsXMLHandler;
import p2pcdnsim.xml.XMLHandler;
import p2pcdnsim.xml.XMLNetworkTopologyBuilder;
import p2pcdnsim.xml.XMLVoDCDNBuilder;
import desmoj.core.simulator.Experiment;
import desmoj.core.simulator.Model;
import desmoj.core.simulator.SimTime;
import desmoj.core.statistic.Accumulate;
import desmoj.core.statistic.Count;

public class SimCDN extends Model {

	public static final int SIM_TIME = 80000;

	public SimCDN(Model owner, String modelName, boolean showInReport, boolean showInTrace) {
		super(owner, modelName, showInReport, showInTrace);
	}

	public String description() {
		return "CDN simulator";
	}

	public void doInitialSchedules() {

		try {
			TopologyConstructor tConstructor = new TopologyConstructor();
			tConstructor.setModel(this);
			tConstructor.setBuilder(new XMLNetworkTopologyBuilder(getRouterDoc(), "100000000", "0.0001", null));
			tConstructor.constructTopology();
			NetworkTopology topology = tConstructor.getNetworkTopology();
			
			CDNConstructor cdnConstructor = new CDNConstructor();
			cdnConstructor.setModel(this);
			cdnConstructor.setBuilder(new XMLVoDCDNBuilder(
					getCacheXMLHandler(),
					getClientPlacementXMLHandler(),
					getVideoObjectsXMLHandler(),
					getRequestsXMLHandler(),
					topology,
					new DynamicReplicaPlacementNaive(true, getRequestsXMLHandler())
					//new GreedyPlacement(true,getRequestsXMLHandler())
					//new HotSpotPlacement(true,getRequestsXMLHandler(),1)
					//new RandomPlacement()
					));
			cdnConstructor.constructCDN();
			CDN cdn = cdnConstructor.getCDN();

			cdn.activate(new SimTime(0.0));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		long startTime = System.currentTimeMillis();
		long finishTime;
		
		// create model and experiment
		SimCDN model = new SimCDN(null, "CDN Simulator", true, true);
		Experiment exp = new Experiment("Simulator");
		model.connectToExperiment(exp);

		// set experiment parameters
		exp.setShowProgressBar(false); // display a progress bar (or not)
		exp.stop(new SimTime(SIM_TIME));
		// time units
		exp.tracePeriod(new SimTime(0.0), new SimTime(1)); // set the period of the trace
		exp.debugPeriod(new SimTime(0.0), new SimTime(1)); // and debug output

		exp.start();
		exp.report();
		exp.finish();

		finishTime = System.currentTimeMillis();
		long time = finishTime - startTime;

		Date date = new Date(time);
		String simulationTime = (new SimpleDateFormat("hh:mm:ss")).format(date);
		System.out.println("Simulation time: " + simulationTime);

	}

	public void init() {
		SimReporter.getInstance().registerReportable(SimReporter.NUMBER_OF_REQUESTS, new Count(this, "Number of Requests", true, false));
		SimReporter.getInstance().registerReportable(SimReporter.HIT_RATIO, new Count(this, "Hit Ratio", true, false));
		SimReporter.getInstance().registerReportable(SimReporter.MISS_RATIO, new Count(this, "Miss Ratio", true, false));		
		SimReporter.getInstance().registerReportable(SimReporter.STARTUP_DELAY, new Accumulate(this, "Startup Delay", true, false));
		SimReporter.getInstance().registerReportable(SimReporter.PACKET_LOSS, new Count(this, "Packet Loss", true, false));
		SimReporter.getInstance().registerReportable(SimReporter.BANDWIDTH_CONSUMPTION, new Bandwidth (this, "Bandwidth Consumption", true, false));
	}

	private String getScenario() {
		return "scenario1";
	}
	
	private Document getRouterDoc() throws JDOMException, IOException {
		String file = "xml/"+getScenario()+"/Routers.xml";
		SAXBuilder builder = new SAXBuilder();
		return builder.build(new File(file));
	}

	private XMLHandler getVideoObjectsXMLHandler() throws JDOMException,
	IOException {
		String file = "xml/"+getScenario()+"/VideoObjects.xml";
		SAXBuilder builder = new SAXBuilder();
		return new VideoObjectsXMLHandler(builder.build(new File(file)),
		"300000");
	}

	private XMLHandler getCacheXMLHandler() throws JDOMException,
	IOException {
		String file = "xml/"+getScenario()+"/Cache.xml";
		SAXBuilder builder = new SAXBuilder();
		return new StandardXMLHandler(builder.build(new File(file)));
	}
	
	private XMLHandler getRequestsXMLHandler() throws JDOMException,
	IOException {
		String file = "xml/"+getScenario()+"/Requests.xml";
		SAXBuilder builder = new SAXBuilder();
		return new StandardXMLHandler(builder.build(new File(file)));
	}

	private XMLHandler getClientPlacementXMLHandler() throws JDOMException,
	IOException {
		String file = "xml/"+getScenario()+"/ClientPlacement.xml";
		SAXBuilder builder = new SAXBuilder();
		return new StandardXMLHandler(builder.build(new File(file)));
	}

}
